﻿using Freebase4net.Rest;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Freebase4net
{
    public class SearchService : BaseService<SearchServiceResponse>
    {
        public SearchService(string apiKey)
            : base(apiKey)
        {
        }

        protected override string _baseUrl
        {
            get { return Constants.SearchServiceUrl; }
        }

        protected override RestClient CreateRequest(dynamic query)
        {
            RestClient client = new RestClient { BaseUrl = string.Format("{0}", _baseUrl) };

            string q = (string)query;
            if (!string.IsNullOrEmpty(q))
            {
                client.AddParameter("query", q);
            }

            if (!string.IsNullOrEmpty(_apiKey))
            {
                client.AddParameter("key", _apiKey);
            }

            client.RequestFormat = DataFormat.Json;
            return client;
        }

        protected override SearchServiceResponse CreateResponse(RestResponseMessage response)
        {
            var freebaseResponse = new SearchServiceResponse
            {
                ResultAsString = response.Content,
                Status = response.StatusCode
            };

            if (freebaseResponse.Status == System.Net.HttpStatusCode.OK)
            {
                JObject content = JObject.Parse(response.Content);
                freebaseResponse.ResultAsObject = content;
                var resultList = (JArray)content["result"];
                foreach (var item in resultList)
                {
                    var res = new SearchResult
                    {
                        Id = (string)item["id"],
                        MID = (string)item["mid"],
                        Name = (string)item["name"],
                        Score = double.Parse((string)item["score"]),
                        Language = (string)item["lang"]
                    };

                    if (item["notable"] != null)
                    {

                        res.Notable = new SearchResult.NotableEmbedded
                        {
                            Id = (string)item["notable"]["id"],
                            Name = (string)item["notable"]["name"],
                        };
                    }
                    freebaseResponse.Results.Add(res);
                }
            }

            return freebaseResponse;
        }

        public SearchServiceResponse Read(
            string query,
            string callback = "",
            string domain = "",
            bool exact = false,
            string filter = "",
            string format = "",
            bool encode = false,
            bool indent = false,
            int limit = 20,
            string rmql_output = "",
            bool prefixed = false,
            int start = 0,
            string type = "",
            string language = ""
            )
        {
            return ReadInternal((dynamic)query, GetParameters(callback, domain, exact, filter, format, encode, indent, limit, rmql_output, prefixed, start, type, language));
        }

        public Task<SearchServiceResponse> ReadAsync(
            string query, 
            string callback = "", 
            string domain = "", 
            bool exact = false, 
            string filter = "", 
            string format = "", 
            bool encode = false, 
            bool indent = false, 
            int limit = 20, 
            string rmql_output = "", 
            bool prefixed = false, 
            int start = 0, 
            string type = "", 
            string language = ""
            )
        {
            return ReadInternalAsync((dynamic)query, GetParameters(callback, domain, exact, filter, format, encode, indent, limit, rmql_output, prefixed, start, type, language));
        }

        private string[] GetParameters(string callback, string domain, bool exact, string filter, string format, bool encode, bool indent, int limit, string rmql_output, bool prefixed, int start, string type, string language)
        {
            List<string> parameters = new List<string>();


            if (!string.IsNullOrEmpty(callback))
                parameters.Add(string.Format("callback,{0}", callback));
            if (!string.IsNullOrEmpty(domain))
                parameters.Add(string.Format("domain,{0}", domain));
            if (!string.IsNullOrEmpty(filter))
                parameters.Add(string.Format("filter,{0}", filter));
            if (!string.IsNullOrEmpty(format))
                parameters.Add(string.Format("format,{0}", format));
            if (!string.IsNullOrEmpty(rmql_output))
                parameters.Add(string.Format("rmql_output,{0}", rmql_output));
            if (!string.IsNullOrEmpty(type))
                parameters.Add(string.Format("type,{0}", type));
            if (!string.IsNullOrEmpty(language))
                parameters.Add(string.Format("lang,{0}", language));

            if (!string.IsNullOrEmpty(callback))
                parameters.Add(string.Format("callback,{0}", callback));
            if (limit != 20)
                parameters.Add(string.Format("limit,{0}", limit));
            if (start != 0)
                parameters.Add(string.Format("start,{0}", start));
            if (exact)
                parameters.Add(string.Format("exact,{0}", exact.ToString().ToLower()));
            if (encode)
                parameters.Add(string.Format("encode,{0}", encode.ToString().ToLower()));
            if (indent)
                parameters.Add(string.Format("indent,{0}", indent.ToString().ToLower()));
            if (prefixed)
                parameters.Add(string.Format("prefixed,{0}", prefixed.ToString().ToLower()));

            return parameters.ToArray();
        }
    }
}
